Podman rootlessUtilisations de volumes

Podman est le nouvel outil pour exécuter des conteneurs . Il est sans démon (contrairement à docker ) et il est conçu pour jouer un peu mieux dans l'écosystème Linux, à partir de zéro.

Podman est architecturé comme les outils Linux classiques - il est léger, il ne demande pas plus d'autorisations qu'il n'en a besoin et il coopère volontiers avec SELinux . (Contrairement à certains d'entre nous !)

Cependant, vous avez peut-être réalisé que certaines commandes qui fonctionnaient bien dans Docker ne fonctionnent tout simplement pas dans Podman ; doublement, lorsque SELinux est aux commandes.

Vous vous arrachez les cheveux (si vous en avez).

Vous obtenez toutes sortes d'erreurs sur les autorisations, et…. vous voulez désespérément éviter de désactiver SELinux, mais vous finissez par rechercher setenforce 0et exécuter tout avec sudo.

Arrêt! 🚏 Non, je veux dire stop . 🛑 Nous pouvons résoudre ce problème.

Dans cet article, je vais expliquer comment partager un volume depuis votre machine hôte avec podman, lorsque vous exécutez des conteneurs sans racine.

Je partagerai également une commande podman que vous pouvez utiliser et qui vous aide vraiment dans ces situations.

Podman sans racine vs racine en un coup d'œil

Comprendre le fonctionnement du podman sans racine

Que sont les espaces de noms d'utilisateur ?

Les conteneurs sans racine partagent le même espace de noms d'utilisateur

Lorsque le conteneur s'exécute, tous les volumes qui sont partagés avec lui apparaîtront dans l'espace de noms de l'utilisateur comme appartenant à root/root.

podman unshare vous permet d'exécuter une commande dans le même espace de noms d'utilisateur que vos conteneurs

Pourquoi s'appelle-t-il unshare"annuler le partage" ?

Comment autoriser un conteneur podman sans racine à écrire sur un volume

Obtenez d'abord l'UID de l'utilisateur du conteneur

Permet podman unshare chownd'accorder à l'ID utilisateur du conteneur des autorisations d'écriture dans votre répertoire

Vérifiez que les autorisations sont correctes, en listant le répertoire à l'intérieur du conteneur

Ou, vous pouvez simplement exécuter votre processus en tant qu'utilisateur root à l'intérieur du conteneur

TLDR

 

Podman sans racine vs racine en un coup d'œil

Lorsque vous exécutez des conteneurs avec Podman, vous allez probablement fonctionner en mode rootless ou rootful . La façon dont vous choisissez d'exécuter Podman affecte l' ID utilisateur sous lequel votre processus s'exécutera. Par conséquent, cela affecte les choses que votre processus conteneurisé est autorisé à faire.

Le tableau ci-dessous montre quatre modes de fonctionnement rootless/rootful possibles de Podman, et comment ils fonctionnent réellement dans la pratique :

Vous exécutez podman en tant que..

Avec un processus conteneurisé exécuté en tant que..

L'UID réel visible sur l'hôte est…

racine

racine

0

racine

non racine

L'UID de l'utilisateur exécutant le processus à l'intérieur du conteneur

non racine

racine

Votre UID

non racine

non racine

Un UID non root

Comme vous pouvez le constater, l'ID utilisateur ultime du processus peut varier considérablement ! Voyons comment cette partie fonctionne.

Comprendre le fonctionnement du podman sans racine

Podman sans racine (exécutant Podman en tant qu'utilisateur non root) doit faire un peu de gymnastique pour obtenir la même expérience de conteneur que vous connaissez de docker , mais sans nécessiter root .

Lorsque vous exécutez podman sans racine, il utilise un espace de noms d'utilisateur pour mapper les ID utilisateur dans le conteneur et les ID utilisateur sur votre hôte.

Que sont les espaces de noms d'utilisateur ?

Les espaces de noms d'utilisateurs sont une fonctionnalité Linux qui vous permet d'encapsuler et d'isoler un processus, de sorte qu'il semble s'exécuter sous son propre ensemble différent d'identités de sécurité, telles que les ID d'utilisateur et les ID de groupe.

Depuis la page de manuel :

Les ID d'utilisateur et de groupe d'un processus peuvent être différents à l'intérieur et à l'extérieur d'un espace de noms d'utilisateur.

Par exemple, un espace de noms d'utilisateur permet à un processus conteneurisé de s'exécuter en tant qu'utilisateur unique à l'intérieur de l'espace de noms d'utilisateur, comme UID 200. Mais en dehors de l'espace de noms d'utilisateur (conteneur), il s'exécute en fait sous un UID complètement différent (par exemple 100199).

Consultez cet excellent article de Dan Walsh (english) sur le fonctionnement des espaces de noms d'utilisateurs avec Podman .

Dans l'espace de noms d'utilisateur de Podman , il existe un nouvel ensemble d'ID d'utilisateur et d'ID de groupe, qui sont distincts des UID et des GID sur votre hôte.

Illustration du mappage des identifiants d'utilisateur entre un parent et un espace de nom d'utilisateurIllustration du mappage des identifiants d'utilisateur entre un parent et un espace de nom d'utilisateur 
 

En utilisant un espace de noms d'utilisateur et en utilisant une carte d'UID, Podman peut faire en sorte qu'un processus de conteneur puisse sembler s'exécuter en tant qu'utilisateur 200 à l'intérieur d'un conteneur, mais en réalité, il s'exécute en tant qu'ID utilisateur différent sur l'hôte.

Vous pouvez voir les mappages réels en affichant le fichier /proc/self/uid_map à l'intérieur de votre conteneur.

Les pages de manuel Linux contiennent beaucoup plus de détails sur la façon dont cela fonctionne. Vérifierman 7 user_namespaces

Les conteneurs sans racine partagent le même espace de noms d'utilisateur

Tous les conteneurs sans racine que vous exécutez sont exécutés dans le même espace de noms d'utilisateur . Les ingénieurs derrière Podman expliquent cela dans cet article sur le processus "en coulisses" de Podman :

Tous les conteneurs sans racine doivent être exécutés dans le même espace de noms d'utilisateur . S'ils ne le sont pas, certaines choses (comme le partage de l'espace de noms réseau à partir d'un autre conteneur) seraient impossibles.

En utilisant le même espace de noms d'utilisateur, vos conteneurs peuvent partager des ressources entre eux, sans avoir besoin de demander des privilèges root.

Il utilise cet espace de noms d'utilisateur pour monter des systèmes de fichiers ou exécuter un conteneur qui accède à plusieurs ID utilisateur (UID) ou ID de groupe (GID).

Ce mappage convient à la plupart des situations, sauf lorsque le conteneur doit pouvoir partager quelque chose avec l'hôte, comme un volume.

Mais - voici la chose importante :

Lorsque le conteneur s'exécute, tous les volumes qui sont partagés avec lui apparaîtront dans l'espace de noms de l'utilisateur comme appartenant à root/root. Parce que le mappage mappera votre UID sur l'hôte (par exemple 1000) en tant que root(0) dans le conteneur.

Voici un exemple de ce que je veux dire. J'exécute podman sans racine en tant qu'utilisateur non root (utilisateur 200) et monte un volume à partir de mon hôte :

$ podman run --user 200 -it -v $(pwd)/myfolder:/mnt/myfolder:Z busybox

À l'intérieur du conteneur, examinez les autorisations sur le répertoire monté :

~ $ ls -al /mnt

total 16

drwxr-xr-t    3 root     root          4096 Jan  3 15:50 .

dr-xr-xr-x   14 root     root          4096 Jan  3 15:50 ..

drwxr-xr-x    2 root     root          4096 Jan  3 15:50 public

Le répertoire appartient à root - pas à l'utilisateur "200", ni à mon ID utilisateur.

Cela signifie que si vous exécutez votre processus de conteneur en tant qu'utilisateur non root, il ne pourra pas écrire dans ce répertoire.

Alors, comment changer le propriétaire du répertoire dans le conteneur, afin que l'utilisateur puisse y écrire ?

Et comment pouvons-nous dépanner et exécuter des commandes dans ce même espace de noms d'utilisateur, lorsque les choses tournent mal, sans avoir à démarrer un conteneur ?

C'est là qu'intervient  podman unshare

podman unshare vous permet d'exécuter une commande dans le même espace de noms d'utilisateur que vos conteneurs

podman unshare exécute une commande dans l'espace de noms d'utilisateur modifié de Podman. Il est destiné à être exécuté avec podman sans racine (où vous exécutez podman en tant qu'utilisateur non root).

Étant donné que Podman utilise des espaces de noms d'utilisateurs pour faire fonctionner la magie de différents identifiants d'utilisateurs et de groupes, il serait utile que nous ayons un moyen d'accéder à ce même espace de noms d'utilisateurs, lorsque nous devons réparer ou enquêter sur quelque chose.

C'est là qu'intervient podman unshare. De la page de manuel pour podman-unshare:

podman unshare est utile pour dépanner les opérations non privilégiées et pour effacer manuellement le stockage et d'autres données liées aux images et aux conteneurs.

Il utilise la commande unshare, partie du noyau Linux. Unshare est l'une des commandes qui rend réellement possibles les espaces de noms d'utilisateurs, et donc les conteneurs .

À partir de la page de manuel Linux pourunshare :

unshare - exécuter le programme dans de nouveaux espaces de noms
La commande unshare crée de nouveaux espaces de noms… puis exécute le programme spécifié.

Pourquoi s'appelle-t-il  unshare"annuler le partage" ?

La raison pour laquelle cela s'appelle annuler le partage n'a rien à voir avec l'annulation du partage de fichiers .

C'est parce qu'il exécute le programme dans un espace de noms qui est séparé ou "non partagé" de son processus parent.

Si vous êtes nouveau dans tout cela, unshare ce n'est pas exactement une commande au nom utile, mais c'est l'histoire de Linux pour vous.

 

Lorsque vous utilisez podman unshare, vous sautez effectivement hors de votre espace de noms normal et dans l' espace de noms d'utilisateur Podman .

C'est comme exécuter la commande unshare en tant que processus Podman. Ainsi, vous pouvez exécuter une commande dans le même espace de noms d'utilisateur, comme modifier les autorisations de fichiers ou parcourir votre système de fichiers, si nécessaire.

Vous pouvez consulter l'article de Dan Walsh sur Opensource.com pour plus d'informations sur le fonctionnement de Podman sans racine .

Alors maintenant, nous savons ce que c'est podman unshare, en quoi est-ce pertinent de partager un annuaire ?

Comment autoriser un conteneur podman sans racine à écrire sur un volume

Cela nous amène donc à la tâche en cours. Si vous souhaitez exécuter podman sans racine pour exécuter des conteneurs, mais que vous souhaitez partager un répertoire depuis votre hôte, comment procédez-vous ?

Je le fais sur mon ordinateur portable, car j'exécute Nexus , le référentiel d'artefacts, dans un conteneur. Je veux qu'il enregistre ses artefacts dans un emplacement sur ma machine hôte, de sorte que si le conteneur meurt, je n'ai pas à tout télécharger à nouveau.

En mettant tout cela ensemble, voici les étapes :

Obtenez d'abord l'UID de l'utilisateur du conteneur

Vous devez d'abord savoir sous quel UID le conteneur s'exécute.

L'utilisateur est spécifié dans le Dockerfile de l'image que vous exécutez (dans la USERligne).

Ou, lorsque vous exécutez le conteneur, vous pouvez définir explicitement l'utilisateur à l'aide de l' podman run --user <id>option.

podman unshare chown Permet d'accorder à l'ID utilisateur du conteneur des autorisations d'écriture dans votre répertoire

Ensuite, nous devons modifier l'UID/GID du répertoire de volume dans l'espace de noms de l'utilisateur Podman sans racine , pour qu'il soit identique à l'UID/GID de l'utilisateur du conteneur.

Dans mon cas, le nexusconteneur s'exécute sous l'UID 200. Je peux voir comment mon conteneur sans racine « verrait » le système de fichiers en utilisant podman unshare:

$ podman unshare ls -al /home/tom/myshares

drwx--x--x. 58 root root   4096 Dec 25 13:45 .

drwx--x--x.  8 root root   4096 Nov 18 16:00 ..

drwxrwxr-x.  6 root root   4096 May 18  2020 nexus2

Comme vous pouvez le voir, le nexus2répertoire appartient à root .

Ce n'est pas bon, car lorsque mon conteneur démarre, il voudra écrire dans ce répertoire. Et puisque l'utilisateur exécutant nexus dans le conteneur est user 200et non root, cela échouera .

J'utilise donc la chowncommande pour définir l'UID/GID du répertoire partagé, et j'exécute cette commande dans mon espace de noms d'utilisateur Podman :

podman unshare chown 200:200 -R /home/tom/myshares/nexus2

Jusqu'ici, tout va bien.

Comment pouvons-nous vérifier que les choses fonctionnent ?

Vérifiez que les autorisations sont correctes, en listant le répertoire à l'intérieur du conteneur

Maintenant, je veux m'assurer que lorsque mon conteneur Nexus démarre, il pourra écrire dans ce dossier.

J'exécute donc le conteneur sans racine. En utilisant l' -voption, je monte mon volume comme /sonatype-workdans le conteneur. Et je remplace le point d'entrée, de sorte que je me lance directement dans un shell ( /bin/sh):

podman run -it --rm --name nexus2 \

    -v /home/tom/myshares/nexus2:/sonatype-work:Z \

    sonatype/nexus /bin/sh

Notez que j'ajoute le drapeau :Z au volume. Cela indique à Podman d'étiqueter le contenu du volume comme "privé non partagé" avec SELinux. Cette étiquette permet au conteneur d'écrire sur le volume, mais ne permet pas de partager le volume avec d'autres conteneurs. Cette syntaxe est également utilisée dans la commande docker .

Une fois à l'intérieur du conteneur, je peux vérifier que je "possède" désormais le répertoire en tant qu'utilisateur nexus. Si je possède le répertoire, je devrais pouvoir y écrire:

$ ls -al / | grep sonatype-work

drwxr-xr-x.  15 nexus nexus 4096 Sep 27 13:29 sonatype-work

Cette commande ls me montre que le sonatype-workrépertoire semble maintenant appartenir à nexus/nexuslorsqu'il se trouve à l'intérieur du conteneur. Résultat!

Lors du prochain démarrage du conteneur, l' utilisateur nexus sera autorisé à écrire dans ce répertoire.

Ou, vous pouvez simplement exécuter votre processus en tant qu'utilisateur root à l'intérieur du conteneur

Une autre option consiste à exécuter en tant rootqu'utilisateur à l'intérieur du conteneur. (Oui, plutôt déroutant, vous pouvez exécuter un conteneur sans racine et définir l'utilisateur du conteneur sur root, et le processus s'exécutera en tant qu'utilisateur non privilégié sur l'hôte )

Pour exécuter votre processus en tant qu'utilisateur root dans le conteneur, utilisez-u root :

podman run -it --rm --name nexus2 \

    -v /home/tom/myshares/nexus2:/sonatype-work:Z \

    -u root \

    sonatype/nexus /bin/sh

N'oubliez pas d'ajouter le suffixe :Z

Maintenant, lorsque j'entrerai dans mon shell sh, je serai root à l'intérieur du conteneur.

Exécuter en tant que root dans le conteneur est un peu plus portable, mais c'est de la triche. Nous ne devrions vraiment rien exécuter en tant que root, même à l'intérieur d'un conteneur. Pour cette raison, cette solution n'est pas recommandée pour les configurations de production.

TLDR